#include "main.h"
#include "soc/soc_misc.h"
#include "lib/stringex.h"
#include "soc/soc_misc.h"
#include "soc_misc.h"
#include "os/osapi.h"

static bool m_isInitSysTick = false;
static uint32_t m_SysTickTotal;
static uint32_t m_SysTickScale;

inline void TryInitSysTick()
{
    if(m_isInitSysTick)
        return;
    if(SysTick->LOAD == 0)
        return;

    m_SysTickTotal = SysTick->LOAD + 1;
    m_SysTickScale = (m_SysTickTotal / 1000);
    m_isInitSysTick = true;
}

uint32_t SOC_Misc::GetCpuFrequency()
{
    return HAL_RCC_GetSysClockFreq();
}

uint32_t SOC_Misc::CurrentCpuUs()
{
    TryInitSysTick();

    if(!m_isInitSysTick)
        return 0;
        
    uint32_t ms = HAL_GetTick();
    uint32_t us = (SysTick->LOAD - SysTick->VAL) / (m_SysTickScale);

    return ms * 1000 + us;
}

uint32_t SOC_Misc::CurrentCpuMilliseconds()
{
    return HAL_GetTick();
}

void SOC_Misc::Delay(uint32_t ms)
{
    HAL_Delay(ms);
}

void SOC_Misc::DelayUs(uint32_t us)
{
    // if(us <= 0)
    //     return;

    //us，lock os，防止被打断，影响精度
    // OsApi::KernelLock();
    
    uint32_t startUs = CurrentCpuUs();
    while ((CurrentCpuUs() - startUs) < us)
    {
    }

    // OsApi::KernelUnLock();
}

/// @brief 未充分验证
/// @param us 
void SOC_Misc::DelayUsHighPrecision(uint32_t us)
{
    static uint32_t total = SysTick->LOAD + 1;
    static uint32_t scale = (total / 1000);

    uint32_t cnt = us * scale;
    uint32_t startCnt = (total - SysTick->VAL);
    while((total - SysTick->VAL) - startCnt < cnt)
    {
        
    }
}

void SOC_Misc::ResetCpu()
{
    HAL_NVIC_SystemReset();
}

std::string SOC_Misc::GetCpuUID()
{
#if defined STM32G4
    uint32_t uid0 = *(__IO uint32_t*)(0x1FFF7A10);
    uint32_t uid1 = *(__IO uint32_t*)(0x1FFF7A14);
    uint32_t uid2 = *(__IO uint32_t*)(0x1FFF7A18);
#else 
    uint32_t uid0 = HAL_GetUIDw0();
    uint32_t uid1 = HAL_GetUIDw1();
    uint32_t uid2 = HAL_GetUIDw2();
#endif

    std::string uid = StringEx::Format("%X%X%X%X%X%X%X%X%X%X%X%X", 
                                        PLAT_GET_BYTE(uid0, 3),
                                        PLAT_GET_BYTE(uid0, 2),
                                        PLAT_GET_BYTE(uid0, 1),
                                        PLAT_GET_BYTE(uid0, 0),
                                        PLAT_GET_BYTE(uid1, 3),
                                        PLAT_GET_BYTE(uid1, 2),
                                        PLAT_GET_BYTE(uid1, 1),
                                        PLAT_GET_BYTE(uid1, 0),
                                        PLAT_GET_BYTE(uid2, 3),
                                        PLAT_GET_BYTE(uid2, 2),
                                        PLAT_GET_BYTE(uid2, 1),
                                        PLAT_GET_BYTE(uid2, 0));

    return uid;
}

uint32_t SOC_Misc::GetFlashSize()
{
    return *(uint16_t*)FLASHSIZE_BASE;
}

void SOC_Misc::EnableGlobalInterrupt()
{
    __set_PRIMASK(0);
}

void SOC_Misc::DisableGlobalInterrupt()
{
    __set_PRIMASK(1);
}
